﻿using System;
using System.Text;
using System.Collections.Generic;
using System.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Independ.Tests.Fakes;

namespace Independ.Tests
{
    [TestClass]
    public class IndependTests
    {
        IUnityContainer container;

        [TestInitialize]
        public void MyTestInitialize() 
        {
            container = new UnityContainer();
        }

        [TestMethod]
        public void RegisterInstance()
        {
            var instance1 = new EmptyClassMock();
            var instance2 = new EmptyClassMock();

            container.RegisterInstance(instance1).RegisterInstance(instance2, "1");
        }

        [TestMethod]
        public void RegisterType_WithInterface()
        {
            container.RegisterType<IEmptyClassMock, EmptyClassMock>();

            var result = container.Resolve<IEmptyClassMock>();
            var result2 = container.Resolve<EmptyClassMock>();

            Assert.IsNotNull(result);
            Assert.IsNotNull(result2);
            Assert.AreNotSame(result, result2);
        }

        [TestMethod]
        public void Resolve()
        {
            var instance1 = new EmptyClassMock();
            var instance2 = new EmptyClassMock();

            container.RegisterInstance(instance1).RegisterInstance(instance2, "1");

            Assert.AreSame(instance1, container.Resolve<EmptyClassMock>());
            Assert.AreSame(instance2, container.Resolve<EmptyClassMock>("1"));
        }

        [TestMethod]
        public void IsRegistered()
        {
            var instance1 = new EmptyClassMock();

            container.RegisterInstance(instance1);

            Assert.IsTrue(container.IsRegistered<EmptyClassMock>());
            Assert.IsFalse(container.IsRegistered<EmptyClassMock>("1"));
        }

        [TestMethod]
        public void Resolve_WithInjectionConstructorAttribute()
        {
            container.RegisterInstance(10);
            container.RegisterInstance(99.0);
            Assert.IsTrue(container.IsRegistered(typeof(int)));

            var result = container.Resolve<InjectionConstructorClassMock>();
            Assert.AreEqual(10, result.X);
            Assert.AreEqual(0, result.Y);
        }

        [TestMethod]
        public void Resolve_WithTwoInjectionConstructorAttribute_ThrowException()
        {
            container.RegisterInstance(10);
            container.RegisterInstance(99.0);

            ExAssert.Throws<ContainerException>(() => container.Resolve<DoubleInjectionConstructorClassMock>());
        }

        [TestMethod]
        public void Resolve_WithTwoEqualsCountArgumentsConstructors_ThrowException()
        {
            container.RegisterInstance(10);
            container.RegisterInstance(99.0);

            ExAssert.Throws<ContainerException>(() => container.Resolve<DoubleConstructorClassMock>());
        }

        [TestMethod]
        public void Resolve_Struct()
        {
            var result = container.Resolve<StructMock>();

            Assert.AreEqual(0, result.x);
        }

        [TestMethod]
        public void Resolve_ClassWithDependency()
        {
            container.RegisterType<IEmptyClassMock, EmptyClassMock>();

            var result = container.Resolve<ChildMock>();

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.Dependency);
        }

        [TestMethod]
        public void Resolve_ClassWithHierarchicalDependency()
        {
            container.RegisterType<IEmptyClassMock, EmptyClassMock>();

            var result = container.Resolve<ParentMock>();

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.Dependency);
            Assert.IsNotNull(result.Dependency.Dependency);
        }

        [TestMethod]
        public void Resolve_ClassWithHierarchicalInterfaceDependency()
        {
            container.RegisterType<IEmptyClassMock, EmptyClassMock>("1");
            container.RegisterType<IChildMock, ChildMock>("1");
            var result = container.Resolve<ParentInterfaceMock>("1");

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.Dependency);
            Assert.IsNotNull(result.Dependency.Dependency);
        }

        [TestMethod]
        public void Resolve_ClassDependencyProperty()
        {
            container.RegisterType<IEmptyClassMock, EmptyClassMock>();
            var result = container.Resolve<ChildMockWithDependencyAttribute>();

            Assert.IsNotNull(result);
            Assert.IsNotNull(result.Dependency);
        }

        [TestMethod]
        public void ResolveAll_ClassWithOptionalParameters()
        {
            container.RegisterInstance(1);
            container.RegisterInstance(2, "1");

            Assert.AreEqual(2, container.ResolveAll<int>().Count());
        }

        [TestMethod]
        public void Resolve_ClassWithOverrideParameters()
        {
            var instance1 = new EmptyClassMock();
            var instance2 = new EmptyClassMock();

            container.RegisterInstance<IEmptyClassMock>(instance1);

            var result1 = container.Resolve<ChildMock>();

            var result2 = container.Resolve<ChildMock>(resolverOverrides: new ParameterOverride("dependency", instance2));

            Assert.IsNotNull(result1);
            Assert.AreSame(instance1, result1.Dependency);

            Assert.IsNotNull(result2);
            Assert.AreSame(instance2, result2.Dependency);

            Assert.AreNotSame(result1.Dependency, result2.Dependency);
        }

        [TestMethod]
        public void RegisterFunc()
        {
            container.Register(c => new EmptyClassMock());

            var result1 = container.Resolve<EmptyClassMock>();
            var result2 = container.Resolve<EmptyClassMock>();

            Assert.IsNotNull(result1);
            Assert.IsNotNull(result2);
            Assert.AreNotSame(result1, result2);
        }
    }
}
